package com.shpng.cheapenglish.manager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.jdo.PersistenceManager;

import com.shpng.cheapenglish.db.User;
import com.shpng.cheapenglish.db.UserUnit;
import com.shpng.cheapenglish.db.UserWord;
import com.shpng.cheapenglish.db.Word;
import com.shpng.cheapenglish.entity.SUser;
import com.shpng.cheapenglish.entity.SUserUnit;
import com.shpng.cheapenglish.entity.SUserWord;
import com.shpng.cheapenglish.entity.SWord;
import com.shpng.cheapenglish.entity.WordType;
import com.shpng.cheapenglish.persistent.PMF;
import com.shpng.cheapenglish.persistent.UserUnitPersistent;
import com.shpng.cheapenglish.persistent.UserWordPersistent;
import com.shpng.cheapenglish.persistent.WordPersistent;

public class WordManager {

	private UserWordPersistent userWordPersistent;

	private WordPersistent wordPersistent;

	private UserUnitPersistent userUnitPersistent;

	private static WordManager wordManager;

	private List<SWord> words = new ArrayList<SWord>();

	private List<SUserWord> userWords = new ArrayList<SUserWord>();

	private List<SUserUnit> userUnits = new ArrayList<SUserUnit>();

	private WordManager() {
		wordPersistent = WordPersistent.getInstance();
		userWordPersistent = UserWordPersistent.getInstance();
		userUnitPersistent = UserUnitPersistent.getInstance();
	}

	public static WordManager getInstance() {
		if (wordManager == null)
			wordManager = new WordManager();
		return wordManager;
	}

	public void initWords() {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		List<Word> dbWords = wordPersistent.getWords(pm);
		for (Word dbWord : dbWords) {
			SWord word = new SWord(dbWord);
			words.add(word);
		}
	}

	public void initUserUnit() {
		UserManager userManager = UserManager.getInstance();
		PersistenceManager pm = PMF.get().getPersistenceManager();
		List<UserUnit> dbUserUnits = userUnitPersistent.getUserUnits(pm);
		for (UserUnit dbUserUnit : dbUserUnits) {
			SUser user = userManager.getUser(dbUserUnit.getUserId());
			SUserUnit userUnit = new SUserUnit(dbUserUnit, user);
			userUnits.add(userUnit);
		}
	}

	public void initUserWords() {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		List<UserWord> dbUserWords = userWordPersistent.getUserWords(pm);
		for (UserWord dbUserWord : dbUserWords) {
			SUserUnit suu = getUserUnit(dbUserWord.getUnitId());
			SWord word = getWord(dbUserWord.getWordId());
			SUserWord userWord = new SUserWord(dbUserWord, suu, word);
			userWords.add(userWord);
		}
	}

	public List<SWord> getAllWords() {
		return words;
	}

	public List<SWord> getWords(User user, String type) {
		List<SWord> words = new ArrayList<SWord>();
		if (WordType.UNREAD.equalsIgnoreCase(type)) {
			for (SUserWord userWord : userWords) {
				if (userWord.getUser().getId() == user.getId()
						&& userWord.getReciteTimes() == 0) {
					words.add(userWord.getWord());
				}
			}

		} else if (WordType.READ.equalsIgnoreCase(type)) {
			for (SUserWord userWord : userWords) {
				if (userWord.getUser().getId() == user.getId()
						&& userWord.getReciteTimes() > 0) {
					words.add(userWord.getWord());
				}
			}
			// TODO need to order
		}
		return words;
	}

	public void addUserWord(SWord word, SUserUnit userUnit) {
		for (SUserWord uw : userWords) {
			if (uw.getWordId() == word.getId()
					&& uw.getUnitId() == userUnit.getId()) {
				return;
			}
		}
		PersistenceManager pm = PMF.get().getPersistenceManager();

		UserWord userWord = new UserWord();
		userWord.setWordId(word.getId());
		userWord.setUnitId(userUnit.getId());
		userWord.setAverageDegree(100);
		userWordPersistent.saveUserWord(userWord, pm);
		SUserWord sUserWord = new SUserWord(userWord, userUnit, word);
		userWords.add(sUserWord);
		pm.close();
	}

	public SUserWord getUserWord(SUser user, long wordId) {
		for (SUserWord suw : userWords) {
			if (suw.getUser().getId() == user.getId()
					&& suw.getWordId() == wordId)
				return suw;
		}
		return null;

	}

	public SWord getWord(Long id) {
		for (SWord sw : words) {
			if (sw.getId() == id)
				return sw;
		}
		return null;
	}

	public List<SUserWord> getUserWords(SUser user) {
		List<SUserWord> result = new ArrayList<SUserWord>();
		for (SUserWord suw : userWords) {
			if (suw.getUser() == user)
				result.add(suw);
		}
		return result;

	}

	public void deleteUserWord(SUserWord uw) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		userWordPersistent.deleteUserWord(uw.getId(), pm);
		pm.close();
		userWords.remove(uw);
	}

	// public void verifyWords() {
	// PersistenceManager pm = PMF.get().getPersistenceManager();
	// List<Word> words = wordPersistent.getWords(pm);
	// Iterator<Word> iterator = words.iterator();
	// while (iterator.hasNext()) {
	// Word word = iterator.next();
	// if (word.getWordString() == null
	// || "".equals(word.getWordString().trim())) {
	// wordPersistent.deleteWord(word, pm);
	// }
	// }
	// pm.close();
	//
	// }

	// public List<Long> getWordIds(SUser user, String unit) {
	// PersistenceManager pm = PMF.get().getPersistenceManager();
	// List<Long> wordIds = new ArrayList<Long>();
	//
	// wordIds = userWordPersistent.getWordIds(user, unit, pm);
	//
	// pm.close();
	// return wordIds;
	// }

	public List<SUserWord> getUserWords() {
		return userWords;

	}

	public void deleteWord(SWord w) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		pm.deletePersistent(w.getWord());
		pm.close();
		words.remove(w);
	}

	public List<SUserUnit> getUserUnits() {
		return userUnits;
	}

	public List<SUserUnit> getUserUnits(SUser user) {
		List<SUserUnit> suus = new ArrayList<SUserUnit>();
		for (SUserUnit suu : userUnits) {
			if (suu.getUserId() == user.getId()) {
				suus.add(suu);
			}
		}
		return suus;
	}

	public void deleteUserUnit(SUserUnit userUnit) {
		PersistenceManager pm = PMF.get().getPersistenceManager();

		pm.deletePersistent(userUnit.getUserUnit());
		pm.close();
		userUnits.remove(userUnit);
	}

	public SUserUnit getUserUnit(long id) {
		for (SUserUnit suu : userUnits) {
			if (suu.getId() == id)
				return suu;
		}
		return null;
	}

	public SUserUnit getUserUnit(String unit, SUser user) {
		for (SUserUnit suu : userUnits) {
			if (suu.getUnit().equals(unit) && suu.getUserId() == user.getId())
				return suu;
		}
		return null;
	}

	public SWord getWord(String wordString) {
		for (SWord w : words) {
			if (w.getWordString().equals(wordString)) {
				return w;
			}
		}
		return null;
	}

	public void saveOrUpdateWord(Word word) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		wordPersistent.saveWord(word, pm);
		pm.close();
	}

	public SWord addWord(String w) {
		Word dbWord = new Word();
		dbWord.setWordString(w);
		saveOrUpdateWord(dbWord);
		SWord word = new SWord(dbWord);
		words.add(word);
		return word;
	}

	public SUserUnit saveOrUpdateUserUnit(String unit, SUser user) {
		UserUnit uu = new UserUnit();
		uu.setUnit(unit);
		uu.setUserId(user.getId());
		PersistenceManager pm = PMF.get().getPersistenceManager();
		userUnitPersistent.saveUserUnit(pm, uu);
		pm.close();
		SUserUnit suu = new SUserUnit(uu, user);
		userUnits.add(suu);
		return suu;
	}

	public List<Long> getWordIdsByDegreeOrder(SUserUnit suu) {
		List<Long> wordIds = new ArrayList<Long>();
		List<SUserWord> uws = new ArrayList<SUserWord>();
		for (SUserWord suw : userWords) {
			if (suw.getUserUnit() == suu) {
				uws.add(suw);
			}
		}
		Collections.sort(uws, new Comparator<SUserWord>() {

			@Override
			public int compare(SUserWord o1, SUserWord o2) {
				return o2.getAverageDegree() - o1.getAverageDegree();
			}
		});
		for (SUserWord uw : uws) {
			wordIds.add(uw.getWord().getId());
		}
		return wordIds;
	}

	public void saveOrUpdateUserWord(UserWord dbUserWord) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		userWordPersistent.saveUserWord(dbUserWord, pm);
		pm.close();
	}

}
